package com.mo.lib.utils

import android.media.ExifInterface
import android.os.Build
import androidx.annotation.DrawableRes
import android.graphics.drawable.Drawable
import android.graphics.drawable.BitmapDrawable
import android.graphics.Bitmap.CompressFormat
import androidx.annotation.ColorInt
import androidx.annotation.FloatRange
import android.annotation.TargetApi
import android.graphics.*
import android.net.Uri
import android.renderscript.RenderScript
import android.renderscript.RenderScript.RSMessageHandler
import android.renderscript.Allocation
import android.renderscript.Element
import android.renderscript.ScriptIntrinsicBlur
import android.text.TextUtils
import android.view.View
import androidx.annotation.IntRange
import com.dylanc.longan.application
import com.mo.lib.Orientation
import java.io.*
import java.lang.Exception
import java.net.HttpURLConnection
import java.net.URL

/**
 * @ author：mo
 * @ data：2017/12/7：16:19
 * @ 功能：bitmap工具类
 */
/**
 * 将图像的旋转角度置为0
 *
 * @param path
 */
fun setPictureDegreeZero(path: String) {
    try {
        val exifInterface = ExifInterface(path) //修正图像的旋转角度，设置其不旋转。这里也可以设置其旋转的角度，可以传值过去， //例如旋转90度，传值ExifInterface.ORIENTATION_ROTATE_90，需要将这个值转换为String类型的
        exifInterface.setAttribute(ExifInterface.TAG_ORIENTATION, "no")
        exifInterface.saveAttributes()
    } catch (e: IOException) {
        e.printStackTrace()
    }
}

/**
 * 获取Asset/ 中的图片
 *
 * @param fileName
 * @return
 */
fun getBitmapAssets(fileName: String): Bitmap? {
    var image: Bitmap? = null
    try {
        val am = application.assets
        val `is` = am.open(fileName)
        image = BitmapFactory.decodeStream(`is`)
        `is`.close()
    } catch (e: Exception) {
        e.printStackTrace()
    }
    return image
}

/**
 * 判断 bitmap 对象是否为空
 *
 * @param src 源图片
 * @return `true`: 是<br></br>`false`: 否
 */
fun isEmptyBitmap(src: Bitmap?): Boolean {
    return src == null || src.width == 0 || src.height == 0
}

/**
 * 获取bitmap大小
 *
 * @param bitmap
 * @return
 */
fun getBitmapSize(bitmap: Bitmap): Int { //SInce API 19
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
        return bitmap.allocationByteCount
    } //Since API 12
    return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB_MR1) {
        bitmap.byteCount
    } else bitmap.rowBytes * bitmap.height
}

/**
 * 图像的放大缩小--根据宽高比例
 *
 * @param bitmap 源位图对象
 * @param scaleX 宽度比例系数
 * @param scaleY 高度比例系数
 * @return 返回位图对象
 */
fun getBitmapScale(bitmap: Bitmap, scaleX: Float, scaleY: Float): Bitmap? {
    return getBitmapScale(bitmap, scaleX, scaleY, false)
}

/**
 * 图像放大缩小--根据宽度和高度
 *
 * @param src
 * @param width
 * @param height
 * @return
 */
fun getBitmapScale(src: Bitmap?, width: Int, height: Int): Bitmap? {
    return getBitmapScale(src, width, height, false)
}

/**
 * 图像的放大缩小--根据宽高比例
 *
 * @param bitmap      源图片
 * @param scaleWidth  缩放宽度倍数
 * @param scaleHeight 缩放高度倍数
 * @param recycle     是否回收
 * @return 缩放后的图片
 */
fun getBitmapScale(bitmap: Bitmap, scaleWidth: Float, scaleHeight: Float, recycle: Boolean): Bitmap? {
    if (isEmptyBitmap(bitmap)) {
        return null
    }
    val matrix = Matrix()
    matrix.setScale(scaleWidth, scaleHeight)
    val ret = Bitmap.createBitmap(bitmap, 0, 0, bitmap.width, bitmap.height, matrix, true)
    if (recycle) {
        recyleBitmap(ret)
    }
    return ret
}

/**
 * 图像放大缩小--根据宽度和高度
 *
 * @param bitmap    源图片
 * @param newWidth  新宽度
 * @param newHeight 新高度
 * @param recycle   是否回收
 * @return
 */
fun getBitmapScale(bitmap: Bitmap?, newWidth: Int, newHeight: Int, recycle: Boolean): Bitmap? {
    if (isEmptyBitmap(bitmap)) {
        return null
    }
    val ret = Bitmap.createScaledBitmap(bitmap!!, newWidth, newHeight, true)
    if (recycle) {
        recyleBitmap(ret)
    }
    return ret
}

/**
 * 获取图片的类型
 *
 * @param path
 * @return
 */
fun getBitmapType(path: String?): String {
    val options = BitmapFactory.Options()
    options.inJustDecodeBounds = true
    BitmapFactory.decodeFile(path, options)
    return options.outMimeType
}

/**
 * 获取图片的形状
 *
 * @param bitmap
 * @return 1 长图 2宽图 3正方形
 */
fun getBitmapShape(bitmap: Bitmap): Int {
    var imgType = 0
    val bitmapWidth = bitmap.width
    val bitmapHeight = bitmap.height
    if (bitmapWidth == bitmapHeight) {
        imgType = 3
    } else if (bitmapWidth > bitmapHeight) {
        imgType = 2
    } else if (bitmapWidth < bitmapHeight) {
        imgType = 1
    }
    return imgType
}

/**
 * 镜像翻转
 */
fun getBitmapForMirror(rawBitmap: Bitmap): Bitmap {
    val matrix = Matrix()
    matrix.postScale(-1f, 1f)
    return Bitmap.createBitmap(rawBitmap, 0, 0, rawBitmap.width, rawBitmap.height, matrix, true)
}

/**
 * 根据角度旋转
 */
fun getBitmapForRotate(bitmap: Bitmap, path: String?): Bitmap? {
    return getBitmapForRotate(bitmap, getRotateDegree(path))
}

/**
 * 根据角度旋转
 */
fun getBitmapForRotate(bm: Bitmap, degree: Int): Bitmap? {
    var returnBm: Bitmap? = null

    // 根据旋转角度，生成旋转矩阵
    val matrix = Matrix()
    matrix.postRotate(degree.toFloat())
    try { // 将原始图片按照旋转矩阵进行旋转，并得到新的图片
        returnBm = Bitmap.createBitmap(bm, 0, 0, bm.width, bm.height, matrix, true)
    } catch (e: OutOfMemoryError) {
    }
    if (returnBm == null) {
        returnBm = bm
    }
    if (bm != returnBm) {
        bm.recycle()
    }
    return returnBm
}

/**
 * 读取图像属性：旋转的角度
 *
 * @param path 图像绝对路径
 * @return degree旋转的角度
 */
fun getRotateDegree(path: String?): Int {
    var degree = 0
    try {
        val exifInterface = ExifInterface(path!!)
        val orientation = exifInterface.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL)
        when (orientation) {
            ExifInterface.ORIENTATION_ROTATE_90  -> degree = 90
            ExifInterface.ORIENTATION_ROTATE_180 -> degree = 180
            ExifInterface.ORIENTATION_ROTATE_270 -> degree = 270
            else                                 -> {
            }
        }
    } catch (e: IOException) {
        e.printStackTrace()
    }
    return degree
}

/**
 * 高级图片质量压缩
 *
 * @param bitmap  位图
 * @param width 压缩后的宽度，单位像素
 */
fun getBitmapForZoom(bitmap: Bitmap, width: Double): Bitmap? { // 将bitmap放至数组中，意在获得bitmap的大小（与实际读取的原文件要大）
    val baos = ByteArrayOutputStream() // 格式、质量、输出流
    bitmap.compress(CompressFormat.JPEG, 80, baos)
    val b = baos.toByteArray()
    val newBitmap = BitmapFactory.decodeByteArray(b, 0, b.size) // 获取bitmap大小 是允许最大大小的多少倍
    return getBitmapForScaleWithWH(newBitmap, width, width * newBitmap.height / newBitmap.width)
}

/***
 * 图片缩放
 * @param bitmap 位图
 * @param w 新的宽度
 * @param h 新的高度
 * @return Bitmap
 */
fun getBitmapForScaleWithWH(bitmap: Bitmap?, w: Double, h: Double): Bitmap? {
    return if (w == 0.0 || h == 0.0 || bitmap == null) {
        bitmap
    } else {
        val width = bitmap.width
        val height = bitmap.height
        val matrix = Matrix()
        val scaleWidth = (w / width).toFloat()
        val scaleHeight = (h / height).toFloat()
        matrix.postScale(scaleWidth, scaleHeight)
        Bitmap.createBitmap(bitmap, 0, 0, width, height, matrix, true)
    }
}

/**
 * 图像质量压缩
 *
 * @param image
 * @param srcPath 要保存的路径
 * @return
 */
fun compressImage(image: Bitmap, srcPath: String?): Bitmap? {
    val baos = ByteArrayOutputStream() // 质量压缩方法，这里100表示不压缩，把压缩后的数据存放到baos中
    image.compress(CompressFormat.JPEG, 100, baos)
    var options = 100 // 循环判断如果压缩后图像是否大于100kb,大于继续压缩
    while (baos.toByteArray().size / 1024 > 100) { // 重置baos即清空baos
        baos.reset() // 每次都减少10
        options -= 10 // 这里压缩options%，把压缩后的数据存放到baos中
        image.compress(CompressFormat.JPEG, options, baos)
    } // 把压缩后的数据baos存放到ByteArrayInputStream中
    val isBm = ByteArrayInputStream(baos.toByteArray()) // 把ByteArrayInputStream数据生成图像
    val bitmap = BitmapFactory.decodeStream(isBm, null, null)
    try {
        val out = FileOutputStream(srcPath)
        bitmap!!.compress(CompressFormat.PNG, 90, out)
    } catch (e: Exception) {
        e.printStackTrace()
    }
    return bitmap
}

/**
 * 读取资源文件中图片
 *
 * @param resId 资源 Id
 * @return Bitmap 对象
 */
fun getBitmap(@DrawableRes resId: Int): Bitmap {
    return BitmapFactory.decodeResource(application.resources, resId) //        return ResUtil.getBitmap(resId);
}

/**
 * File 转 Bitmap
 *
 * @param file 文件
 * @return bitmap
 */
fun getBitmap(file: File?): Bitmap? {
    return if (file == null) null else BitmapFactory.decodeFile(file.absolutePath)
}

/**
 * Uri 转 Bitmap
 *
 * @param imageUri
 * @return
 */
fun getBitmap(imageUri: Uri): Bitmap? {
    var bitmap: Bitmap? = null
    try {
        bitmap = BitmapFactory.decodeStream(application.contentResolver.openInputStream(imageUri))
    } catch (e: FileNotFoundException) {
        e.printStackTrace()
    }
    return bitmap
}

/**
 * InputStream 转 Bitmap
 *
 * @param is 输入流
 * @return bitmap
 */
fun getBitmap(`is`: InputStream?): Bitmap? {
    return if (`is` == null) null else BitmapFactory.decodeStream(`is`)
}

/**
 * url 转 Bitmap
 *
 * @param url
 * @return
 */
fun getBitmap(url: String?): Bitmap? {
    var u: URL? = null
    var bmp: Bitmap? = null
    try {
        u = URL(url)
    } catch (e: Exception) { // TODO: handle exception
    }
    try {
        val conn = u!!.openConnection() as HttpURLConnection
        conn.connectTimeout = 0
        conn.doInput = true
        conn.connect()
        val ins = conn.inputStream
        bmp = BitmapFactory.decodeStream(ins)
        ins.close()
    } catch (e: Exception) { // TODO: handle exception
    }
    return bmp
}

/**
 * filePath 转 Bitmap
 *
 * @param filePath 文件路径
 * @return bitmap
 */
fun getBitmap2(filePath: String): Bitmap {
    return BitmapFactory.decodeFile(filePath.trim { it <= ' ' }) //        FileInputStream fis = null;
    //        try {
    //            fis = new FileInputStream(filePath);
    //        } catch (FileNotFoundException e) {
    //            e.printStackTrace();
    //        }
    //        Bitmap bitmap = BitmapFactory.decodeStream(fis);
}

/**
 * FileDescriptor 转 Bitmap
 *
 * @param fd 文件描述
 * @return bitmap
 */
fun getBitmap(fd: FileDescriptor?): Bitmap? {
    return if (fd == null) null else BitmapFactory.decodeFileDescriptor(fd)
}

/**
 * Drawable 转 Bitmap
 *
 * @param drawable
 * @return
 */
fun getBitmap(drawable: Drawable): Bitmap {
    if (drawable is BitmapDrawable) {
        val bitmapDrawable = drawable
        if (bitmapDrawable.bitmap != null) {
            return bitmapDrawable.bitmap
        }
    }
    val bitmap: Bitmap
    bitmap = if (drawable.intrinsicWidth <= 0 || drawable.intrinsicHeight <= 0) {
        Bitmap.createBitmap(1, 1, if (drawable.opacity != PixelFormat.OPAQUE) Bitmap.Config.ARGB_8888 else Bitmap.Config.RGB_565)
    } else {
        Bitmap.createBitmap(drawable.intrinsicWidth, drawable.intrinsicHeight, if (drawable.opacity != PixelFormat.OPAQUE) Bitmap.Config.ARGB_8888 else Bitmap.Config.RGB_565)
    }
    val canvas = Canvas(bitmap)
    drawable.setBounds(0, 0, canvas.width, canvas.height)
    drawable.draw(canvas)
    return bitmap
}

/**
 * view 转 bitmap
 *
 * @param view 视图
 * @return bitmap
 */
fun getBitmap(view: View?): Bitmap? {
    if (view == null) {
        return null
    }
    val ret = Bitmap.createBitmap(view.width, view.height, Bitmap.Config.ARGB_8888)
    val canvas = Canvas(ret)
    val bgDrawable = view.background
    if (bgDrawable != null) {
        bgDrawable.draw(canvas)
    } else {
        canvas.drawColor(Color.WHITE)
    }
    view.draw(canvas)
    return ret
}

fun getBitmap2(addViewContent: View): Bitmap {
    addViewContent.isDrawingCacheEnabled = true
    addViewContent.measure(View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED), View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED))
    addViewContent.layout(0, 0, addViewContent.measuredWidth, addViewContent.measuredHeight)
    addViewContent.buildDrawingCache()
    val cacheBitmap = addViewContent.drawingCache
    return Bitmap.createBitmap(cacheBitmap)
}

/**
 * bitmap转为drawable
 *
 * @param bitmap 转为drawable 的bitmap
 * @return 返回drawable
 */
fun toDrawable(bitmap: Bitmap?): Drawable? {
    return if (bitmap == null) null else BitmapDrawable(application.resources, bitmap)
}

/**
 * byte[]转Bitmap
 *
 * @param bytes
 * @return
 */
fun getBitmap(bytes: ByteArray?): Bitmap? {
    return if (bytes == null || bytes.size == 0) null else BitmapFactory.decodeByteArray(bytes, 0, bytes.size)
}

/**
 * bitmap转bytes
 */
fun getBytes(bitmap: Bitmap?, quality: Int): ByteArray? {
    if (bitmap == null) {
        return null
    }
    val size = bitmap.width * bitmap.height * 4
    val out = ByteArrayOutputStream(size)
    return try {
        bitmap.compress(CompressFormat.JPEG, quality, out)
        out.flush()
        out.close()
        out.toByteArray()
    } catch (e: IOException) {
        null
    }
}

/**
 * Bitmap转byte[]
 *
 * @param bitmap
 * @param format CompressFormat.PNG/Bitmap.CompressFormat.JPEG
 * @return
 */
fun bitmap2Byte(bitmap: Bitmap?, format: CompressFormat?): ByteArray? {
    if (bitmap == null) {
        return null
    }
    val baos = ByteArrayOutputStream()
    bitmap.compress(format, 100, baos)
    return baos.toByteArray()
}

/**
 * 如果bitmap没有被回收，则强制回收bitmap
 *
 * @param bitmap
 */
fun recyleBitmap(bitmap: Bitmap) {
    if (!bitmap.isRecycled) {
        bitmap.recycle()
    }
}

/**
 * 获取圆形图像
 *
 * @param bitmap 传入Bitmap对象
 * @return 返回圆形的bitmap
 */
fun getBitmapRound(bitmap: Bitmap): Bitmap? {
    return getBitmapRound(bitmap, 0, -0xbdbdbe, false)
}

/**
 * 获取圆形图像
 *
 * @param src         源图片
 * @param borderSize  边框尺寸
 * @param borderColor 边框颜色
 * @param recycle     是否回收
 * @return
 */
fun getBitmapRound(src: Bitmap, @IntRange(from = 0) borderSize: Int, @ColorInt borderColor: Int, recycle: Boolean): Bitmap? {
    if (isEmptyBitmap(src)) {
        return null
    }
    val width = src.width
    val height = src.height
    val size = Math.min(width, height)
    val paint = Paint(Paint.ANTI_ALIAS_FLAG)
    val ret = Bitmap.createBitmap(width, height, src.config)
    val center = size / 2f
    val rectF = RectF(0f, 0f, width.toFloat(), height.toFloat())
    rectF.inset((width - size) / 2f, (height - size) / 2f)
    val matrix = Matrix()
    matrix.setTranslate(rectF.left, rectF.top)
    matrix.preScale(size.toFloat() / width, size.toFloat() / height)
    val shader = BitmapShader(src, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP)
    shader.setLocalMatrix(matrix)
    paint.shader = shader
    val canvas = Canvas(ret)
    canvas.drawRoundRect(rectF, center, center, paint)
    if (borderSize > 0) {
        paint.shader = null
        paint.color = borderColor
        paint.style = Paint.Style.STROKE
        paint.strokeWidth = borderSize.toFloat()
        val radius = center - borderSize / 2f
        canvas.drawCircle(width / 2f, height / 2f, radius, paint)
    }
    if (recycle) {
        recyleBitmap(src)
    }
    return ret
}

/**
 * 获取浮雕效果的图像
 *
 * @param bitmap 图像
 * @return bmp
 */
fun getBitmapRelief(bitmap: Bitmap): Bitmap {
    val width = bitmap.width
    val height = bitmap.height
    val bmp = Bitmap.createBitmap(bitmap.width, bitmap.height, Bitmap.Config.ARGB_8888)
    val oldPx = IntArray(width * height)
    bitmap.getPixels(oldPx, 0, width, 0, 0, width, height)
    var r: Int
    var g: Int
    var b: Int
    var a: Int
    var r1: Int
    var g1: Int
    var b1: Int
    var a1: Int
    var color: Int
    var colorBefore: Int
    val newPx = IntArray(width * height)
    for (i in 1 until width * height) {
        colorBefore = oldPx[i - 1]
        r = Color.red(colorBefore)
        g = Color.green(colorBefore)
        b = Color.blue(colorBefore)
        a = Color.alpha(colorBefore)
        color = oldPx[i]
        r1 = Color.red(color)
        g1 = Color.green(color)
        b1 = Color.blue(color)
        a1 = Color.alpha(color)
        r = r - r1 + 127
        g = g - g1 + 127
        b = b - b1 + 127
        if (r > 255) {
            r = 255
        } else if (r < 0) {
            r = 0
        }
        if (g > 255) {
            g = 255
        } else if (g < 0) {
            g = 0
        }
        if (b > 255) {
            b = 255
        } else if (b < 0) {
            b = 0
        }
        newPx[i] = Color.argb(a, r, g, b)
    }
    bmp.setPixels(newPx, 0, width, 0, 0, width, height)
    return bmp
}

/**
 * 怀旧特效
 *
 * @param bmp 原图片
 * @return
 */
fun getBitmapOld(bmp: Bitmap): Bitmap {
    val width = bmp.width
    val height = bmp.height
    val bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.RGB_565)
    var pixColor = 0
    var pixR = 0
    var pixG = 0
    var pixB = 0
    var newR = 0
    var newG = 0
    var newB = 0
    val pixels = IntArray(width * height)
    bmp.getPixels(pixels, 0, width, 0, 0, width, height)
    for (i in 0 until height) {
        for (k in 0 until width) {
            pixColor = pixels[width * i + k]
            pixR = Color.red(pixColor)
            pixG = Color.green(pixColor)
            pixB = Color.blue(pixColor)
            newR = (0.393 * pixR + 0.769 * pixG + 0.189 * pixB).toInt()
            newG = (0.349 * pixR + 0.686 * pixG + 0.168 * pixB).toInt()
            newB = (0.272 * pixR + 0.534 * pixG + 0.131 * pixB).toInt()
            val newColor = Color.argb(255, if (newR > 255) 255 else newR, if (newG > 255) 255 else newG, if (newB > 255) 255 else newB)
            pixels[width * i + k] = newColor
        }
    }
    bitmap.setPixels(pixels, 0, width, 0, 0, width, height)
    return bitmap
}

/**
 * 获取底片效果的图像
 *
 * @param bitmap 图像
 * @return bmp
 */
fun getBitmapNegative(bitmap: Bitmap): Bitmap {
    val width = bitmap.width
    val height = bitmap.height
    val bmp = Bitmap.createBitmap(bitmap.width, bitmap.height, Bitmap.Config.ARGB_8888)
    val oldPx = IntArray(width * height)
    bitmap.getPixels(oldPx, 0, width, 0, 0, width, height)
    var r: Int
    var g: Int
    var b: Int
    var a: Int
    var color: Int
    val newPx = IntArray(width * height)
    for (i in 0 until width * height) {
        color = oldPx[i]
        r = Color.red(color)
        g = Color.green(color)
        b = Color.blue(color)
        a = Color.alpha(color)
        r = 255 - r
        g = 255 - g
        b = 255 - b
        if (r > 255) {
            r = 255
        } else if (r < 0) {
            r = 0
        }
        if (g > 255) {
            g = 255
        } else if (g < 0) {
            g = 0
        }
        if (b > 255) {
            b = 255
        } else if (b < 0) {
            b = 0
        }
        newPx[i] = Color.argb(a, r, g, b)
    }
    bmp.setPixels(newPx, 0, width, 0, 0, width, height)
    return bmp
}

/**
 * 获取带圆角的图像
 *
 * @param bitmap
 * @param radius
 * @return
 */
fun getBitmapRadius(bitmap: Bitmap, radius: Int): Bitmap? {
    return getBitmapRadius(bitmap, radius.toFloat(), 0, -0xbdbdbe, false)
}

/**
 * 转为圆角图片
 *
 * @param src         源图片
 * @param radius      圆角的度数
 * @param borderSize  边框尺寸
 * @param borderColor 边框颜色
 * @param recycle     是否回收
 * @return 圆角图片
 */
fun getBitmapRadius(src: Bitmap, radius: Float, @IntRange(from = 0) borderSize: Int, @ColorInt borderColor: Int, recycle: Boolean): Bitmap? {
    if (isEmptyBitmap(src)) {
        return null
    }
    val width = src.width
    val height = src.height
    val paint = Paint(Paint.ANTI_ALIAS_FLAG)
    val ret = Bitmap.createBitmap(width, height, src.config)
    val shader = BitmapShader(src, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP)
    paint.shader = shader
    val canvas = Canvas(ret)
    val rectF = RectF(0f, 0f, width.toFloat(), height.toFloat())
    val halfBorderSize = borderSize / 2f
    rectF.inset(halfBorderSize, halfBorderSize)
    canvas.drawRoundRect(rectF, radius, radius, paint)
    if (borderSize > 0) {
        paint.shader = null
        paint.color = borderColor
        paint.style = Paint.Style.STROKE
        paint.strokeWidth = borderSize.toFloat()
        paint.strokeCap = Paint.Cap.ROUND
        canvas.drawRoundRect(rectF, radius, radius, paint)
    }
    if (recycle && !src.isRecycled) {
        src.recycle()
    }
    return ret
}

/**
 * 转为 alpha 位图
 *
 * @param src     源图片
 * @param recycle 是否回收
 * @return alpha 位图
 */
fun getBitmapAlpha(src: Bitmap, recycle: Boolean): Bitmap? {
    if (isEmptyBitmap(src)) return null
    val ret = src.extractAlpha()
    if (recycle && !src.isRecycled) src.recycle()
    return ret
}

/**
 * 添加边框
 *
 * @param src          源图片
 * @param borderSize   边框尺寸
 * @param color        边框颜色
 * @param isCircle     是否画圆
 * @param cornerRadius 圆角半径
 * @param recycle      是否回收
 * @return 边框图
 */
fun getBitmapBorder(src: Bitmap, @IntRange(from = 1) borderSize: Int, @ColorInt color: Int, isCircle: Boolean, cornerRadius: Float, recycle: Boolean): Bitmap? {
    if (isEmptyBitmap(src)) {
        return null
    }
    val ret = if (recycle) src else src.copy(src.config, true)
    val width = ret.width
    val height = ret.height
    val canvas = Canvas(ret)
    val paint = Paint(Paint.ANTI_ALIAS_FLAG)
    paint.color = color
    paint.style = Paint.Style.STROKE
    paint.strokeWidth = borderSize.toFloat()
    if (isCircle) {
        val radius = Math.min(width, height) / 2f - borderSize / 2f
        canvas.drawCircle(width / 2f, height / 2f, radius, paint)
    } else {
        val halfBorderSize = borderSize shr 1
        val rectF = RectF(halfBorderSize.toFloat(), halfBorderSize.toFloat(), (width - halfBorderSize).toFloat(), (height - halfBorderSize).toFloat())
        canvas.drawRoundRect(rectF, cornerRadius, cornerRadius, paint)
    }
    return ret
}

/**
 * 添加文字水印
 *
 * @param src      源图片
 * @param content  水印文本
 * @param textSize 水印字体大小
 * @param color    水印字体颜色
 * @param x        起始坐标 x
 * @param y        起始坐标 y
 * @param recycle  是否回收
 * @return 带有文字水印的图片
 */
fun getBitmapTextWatermark(src: Bitmap, content: String?, textSize: Float, @ColorInt color: Int, x: Float, y: Float, recycle: Boolean): Bitmap? {
    if (isEmptyBitmap(src) || content == null) {
        return null
    }
    val ret = src.copy(src.config, true)
    val paint = Paint(Paint.ANTI_ALIAS_FLAG)
    val canvas = Canvas(ret)
    paint.color = color
    paint.textSize = textSize
    val bounds = Rect()
    paint.getTextBounds(content, 0, content.length, bounds)
    canvas.drawText(content, x, y + textSize, paint)
    if (recycle && !src.isRecycled) {
        src.recycle()
    }
    return ret
}

/**
 * 添加图片水印(叠加)
 *
 * @param src     源图片
 * @param tip     图片水印
 * @param x       起始坐标 x
 * @param y       起始坐标 y
 * @param alpha   透明度
 * @param recycle 是否回收
 * @return 带有图片水印的图片
 */
fun getBitmapImageWatermark(src: Bitmap, tip: Bitmap?, x: Int, y: Int, @IntRange(from = 0, to = 255) alpha: Int, recycle: Boolean): Bitmap? {
    if (isEmptyBitmap(src)) {
        return null
    }
    val ret = src.copy(src.config, true)
    if (!isEmptyBitmap(tip)) {
        val paint = Paint(Paint.ANTI_ALIAS_FLAG)
        val canvas = Canvas(ret)
        paint.alpha = alpha
        canvas.drawBitmap(tip!!, x.toFloat(), y.toFloat(), paint)
    }
    if (recycle && !src.isRecycled) {
        src.recycle()
    }
    return ret
}

/**
 * 盖印颜色蒙层
 *
 * @param src   源 Bitmap 对象
 * @param color 盖印颜色
 * @return 盖印后的图片
 */
fun getBitmapColorMask(src: Bitmap, color: Int): Bitmap? {
    if (isEmptyBitmap(src)) {
        return null
    }
    val ret = src.copy(src.config, true)
    val canvas = Canvas(ret)
    canvas.drawColor(color)
    return ret
}

/**
 * 获取拼接图像
 *
 * @param firstBitmap
 * @param secondBitmap
 * @param orientation  拼接方向
 * @return
 */
fun getBitmapSplicing(firstBitmap: Bitmap?, secondBitmap: Bitmap?, orientation: Orientation): Bitmap? {
    if (firstBitmap == null) {
        return null
    }
    if (secondBitmap == null) {
        return firstBitmap
    }
    val fw = firstBitmap.width
    val fh = firstBitmap.height
    val sw = secondBitmap.width
    val sh = secondBitmap.height
    var bitmap: Bitmap? = null
    var canvas: Canvas? = null
    if (orientation === Orientation.TOP) {
        bitmap = Bitmap.createBitmap(if (sw > fw) sw else fw, fh + sh, Bitmap.Config.ARGB_8888)
        canvas = Canvas(bitmap)
        canvas.drawBitmap(secondBitmap, 0f, 0f, null)
        canvas.drawBitmap(firstBitmap, 0f, sh.toFloat(), null)
    } else if (orientation === Orientation.BOTTOM) {
        bitmap = Bitmap.createBitmap(if (fw > sw) fw else sw, fh + sh, Bitmap.Config.ARGB_8888)
        canvas = Canvas(bitmap)
        canvas.drawBitmap(firstBitmap, 0f, 0f, null)
        canvas.drawBitmap(secondBitmap, 0f, fh.toFloat(), null)
    } else if (orientation === Orientation.LEFT) {
        bitmap = Bitmap.createBitmap(fw + sw, if (sh > fh) sh else fh, Bitmap.Config.ARGB_8888)
        canvas = Canvas(bitmap)
        canvas.drawBitmap(secondBitmap, 0f, 0f, null)
        canvas.drawBitmap(firstBitmap, sw.toFloat(), 0f, null)
    } else if (orientation === Orientation.RIGHT) {
        bitmap = Bitmap.createBitmap(fw + sw, if (fh > sh) fh else sh, Bitmap.Config.ARGB_8888)
        canvas = Canvas(bitmap)
        canvas.drawBitmap(firstBitmap, 0f, 0f, null)
        canvas.drawBitmap(secondBitmap, fw.toFloat(), 0f, null)
    }
    return bitmap
}

/**
 * 获取带倒影图像
 *
 * @param src              原图
 * @param reflectionHeight 倒影高度
 * @param spacing          间距
 * @param recycle          是否回收
 * @return
 */
fun getBitmapReflection(src: Bitmap, reflectionHeight: Int, spacing: Int, recycle: Boolean): Bitmap? {
    if (isEmptyBitmap(src)) {
        return null
    }
    val srcWidth = src.width
    val srcHeight = src.height
    val matrix = Matrix()
    matrix.preScale(1f, -1f)
    val reflectionBitmap = Bitmap.createBitmap(src, 0, srcHeight - reflectionHeight, srcWidth, reflectionHeight, matrix, false)
    val ret = Bitmap.createBitmap(srcWidth, srcHeight + reflectionHeight, src.config)
    val canvas = Canvas(ret) //  绘制原图像
    canvas.drawBitmap(src, 0f, 0f, null) // 绘制倒影图像
    canvas.drawBitmap(reflectionBitmap, 0f, (srcHeight + spacing).toFloat(), null)
    val paint = Paint(Paint.ANTI_ALIAS_FLAG) // 线性渲染-沿Y轴高到低渲染
    val shader: LinearGradient = LinearGradient(0f, srcHeight.toFloat(), 0f, (ret.height + spacing).toFloat(), 0x70FFFFFF, 0x00FFFFFF, Shader.TileMode.MIRROR)
    paint.shader = shader // 取两层绘制交集，显示下层。
    paint.xfermode = PorterDuffXfermode(PorterDuff.Mode.DST_IN) // 绘制渲染倒影的矩形
    canvas.drawRect(0f, (srcHeight + spacing).toFloat(), srcWidth.toFloat(), ret.height.toFloat(), paint)
    if (!reflectionBitmap.isRecycled) {
        reflectionBitmap.recycle()
    }
    if (recycle && !src.isRecycled) {
        src.recycle()
    }
    return ret
}

/**
 * 获取只有倒影的图像
 *
 * @param src
 * @return
 */
fun getBitmapReflectionSingle(src: Bitmap): Bitmap {
    val w = src.width
    val h = src.height // 绘制高质量32位图
    val bitmap = Bitmap.createBitmap(w, h / 2, Bitmap.Config.ARGB_8888) // 创建沿X轴的倒影图像
    val m = Matrix()
    m.setScale(1f, -1f)
    val t_bitmap = Bitmap.createBitmap(src, 0, h / 2, w, h / 2, m, true)
    val canvas = Canvas(bitmap)
    val paint = Paint() // 绘制倒影图像
    canvas.drawBitmap(t_bitmap, 0f, 0f, paint) // 线性渲染-沿Y轴高到低渲染
    val shader: Shader = LinearGradient(0f, 0f, 0f, (h / 2).toFloat(), 0x70ffffff, 0x00ffffff, Shader.TileMode.MIRROR)
    paint.shader = shader // 取两层绘制交集。显示下层。
    paint.xfermode = PorterDuffXfermode(PorterDuff.Mode.DST_IN) // 绘制渲染倒影的矩形
    canvas.drawRect(0f, 0f, w.toFloat(), (h / 2).toFloat(), paint)
    return bitmap
}

/**
 * 获取置灰效果图像
 *
 * @param src
 * @return
 */
fun getBitmapGrey(src: Bitmap): Bitmap {
    return getBitmap(src, 0f, 0f, 1f)
}

/**
 * 设置图像 色调，饱和度，亮度
 *
 * @param bitmap
 * @param rotate     色调(对比度,色相)；正负180（0=原图）
 * @param saturation 饱和度：0-2（0=置灰，0-1=减小饱和度，1=原图，大于1=增加饱和度，大于2也可以，但是基本没法看了）
 * @param scale      亮度；0-2（0=纯黑 1=原图 2=凑合能看，大于2也可以，但是基本没法看了）
 * @return
 */
fun getBitmap(bitmap: Bitmap, rotate: Float, saturation: Float, scale: Float): Bitmap { // 创建副本，用于将处理过的图片展示出来而不影响原图，Android系统也不允许直接修改原图
    val bmp = Bitmap.createBitmap(bitmap.width, bitmap.height, Bitmap.Config.ARGB_8888)
    val canvas = Canvas(bmp)
    val paint = Paint(Paint.ANTI_ALIAS_FLAG)

    // 修改色调,即色彩矩阵围绕某种颜色分量旋转
    val rotateMatrix = ColorMatrix()

    // 0,1,2分别代表像素点颜色矩阵中的Red，Green,Blue分量
    // 控制让红色区在色轮上旋转的角度
    rotateMatrix.setRotate(0, rotate) // 控制让绿红色区在色轮上旋转的角度
    rotateMatrix.setRotate(1, rotate) // 控制让蓝色区在色轮上旋转的角度
    rotateMatrix.setRotate(2, rotate)

    // 修改饱和度
    val saturationMatrix = ColorMatrix()
    saturationMatrix.setSaturation(saturation)

    // 修改亮度，即某种颜色分量的缩放
    val scaleMatrix = ColorMatrix() // 分别代表三个颜色分量的亮度,红、绿、蓝三分量按相同的比例,最后一个参数1表示透明度不做变化
    scaleMatrix.setScale(scale, scale, scale, 1f)

    //将三种效果结合
    val imageMatrix = ColorMatrix()
    imageMatrix.postConcat(rotateMatrix)
    imageMatrix.postConcat(saturationMatrix)
    imageMatrix.postConcat(scaleMatrix)
    paint.colorFilter = ColorMatrixColorFilter(imageMatrix)
    canvas.drawBitmap(bitmap, 0f, 0f, paint)
    return bmp
}

/**
 * 裁剪图片
 *
 * @param src     源图片
 * @param x       开始坐标 x
 * @param y       开始坐标 y
 * @param width   裁剪宽度
 * @param height  裁剪高度
 * @param recycle 是否回收
 * @return 裁剪后的图片
 */
fun getBitmapClip(src: Bitmap, x: Int, y: Int, width: Int, height: Int, recycle: Boolean): Bitmap? {
    if (isEmptyBitmap(src)) {
        return null
    }
    val ret = Bitmap.createBitmap(src, x, y, width, height)
    if (recycle && !src.isRecycled) {
        src.recycle()
    }
    return ret
}

/**
 * 倾斜图片
 *
 * @param src     源图片
 * @param kx      倾斜因子 x    正数=向左 负数=向右
 * @param ky      倾斜因子 y     正数=向下 负数=向上
 * @param px      平移因子 x
 * @param py      平移因子 y
 * @param recycle 是否回收
 * @return 倾斜后的图片
 */
fun getBitmapSkew(src: Bitmap, kx: Float, ky: Float, px: Float, py: Float, recycle: Boolean): Bitmap? {
    if (isEmptyBitmap(src)) {
        return null
    }
    val matrix = Matrix()
    matrix.setSkew(kx, ky, px, py)
    val ret = Bitmap.createBitmap(src, 0, 0, src.width, src.height, matrix, true)
    if (recycle && !src.isRecycled) {
        src.recycle()
    }
    return ret
}

/**
 * 偏移效果
 *
 * @param origin 原图
 * @return 偏移后的bitmap
 */
fun scaleBitmap(origin: Bitmap?, ratio: Float): Bitmap? {
    if (origin == null) {
        return null
    }
    val width = origin.width
    val height = origin.height
    val matrix = Matrix()
    matrix.preScale(ratio, ratio)
    val newBM = Bitmap.createBitmap(origin, 0, 0, width, height, matrix, false)
    if (newBM == origin) {
        return newBM
    }
    origin.recycle()
    return newBM
}

/**
 * 旋转图片
 *
 * @param src     源图片
 * @param degrees 旋转角度
 * @param px      旋转点横坐标    没试出怎么用 直接给0
 * @param py      旋转点纵坐标    没试出怎么用 直接给0
 * @param recycle 是否回收
 * @return 旋转后的图片
 */
fun getBitmapRotate(src: Bitmap, degrees: Int, px: Float, py: Float, recycle: Boolean): Bitmap? {
    if (isEmptyBitmap(src)) {
        return null
    }
    if (degrees == 0) {
        return src
    }
    val matrix = Matrix()
    matrix.setRotate(degrees.toFloat(), px, py)
    val ret = Bitmap.createBitmap(src, 0, 0, src.width, src.height, matrix, true)
    if (recycle && !src.isRecycled) {
        src.recycle()
    }
    return ret
}

/**
 * LOMO特效
 *
 * @param bitmap 原图片
 * @return
 */
fun getBitmapLomo(bitmap: Bitmap): Bitmap {
    val width = bitmap.width
    val height = bitmap.height
    val dst = IntArray(width * height)
    bitmap.getPixels(dst, 0, width, 0, 0, width, height)
    val ratio = if (width > height) height * 32768 / width else width * 32768 / height
    val cx = width shr 1
    val cy = height shr 1
    val max = cx * cx + cy * cy
    val min = (max * (1 - 0.8f)).toInt()
    val diff = max - min
    var ri: Int
    var gi: Int
    var bi: Int
    var dx: Int
    var dy: Int
    var distSq: Int
    var v: Int
    var R: Int
    var G: Int
    var B: Int
    var value: Int
    var pos: Int
    var pixColor: Int
    var newR: Int
    var newG: Int
    var newB: Int
    for (y in 0 until height) {
        for (x in 0 until width) {
            pos = y * width + x
            pixColor = dst[pos]
            R = Color.red(pixColor)
            G = Color.green(pixColor)
            B = Color.blue(pixColor)
            value = if (R < 128) R else 256 - R
            newR = value * value * value / 64 / 256
            newR = if (R < 128) newR else 255 - newR
            value = if (G < 128) G else 256 - G
            newG = value * value / 128
            newG = if (G < 128) newG else 255 - newG
            newB = B / 2 + 0x25

            // ==========边缘黑暗==============//
            dx = cx - x
            dy = cy - y
            if (width > height) {
                dx = dx * ratio shr 15
            } else {
                dy = dy * ratio shr 15
            }
            distSq = dx * dx + dy * dy
            if (distSq > min) {
                v = (max - distSq shl 8) / diff
                v *= v
                ri = newR * v shr 16
                gi = newG * v shr 16
                bi = newB * v shr 16
                newR = if (ri > 255) 255 else if (ri < 0) 0 else ri
                newG = if (gi > 255) 255 else if (gi < 0) 0 else gi
                newB = if (bi > 255) 255 else if (bi < 0) 0 else bi
            } // ==========边缘黑暗end==============//
            dst[pos] = Color.rgb(newR, newG, newB)
        }
    }
    val acrossFlushBitmap = Bitmap.createBitmap(width, height, Bitmap.Config.RGB_565)
    acrossFlushBitmap.setPixels(dst, 0, width, 0, 0, width, height)
    return acrossFlushBitmap
}
/**
 * 暖意特效
 *
 * @param bmp 原图片
 * @param centerX 光源横坐标
 * @param centerY 光源纵坐标
 * @return
 */
/**
 * 暖意特效
 *
 * @param bmp      原图片
 * @param centerX  光源横坐标
 * @param centerY  光源纵坐标
 * @param strength 光照强度 100~200 可以更高，但是效果不好
 * @return
 */
fun warmthFilter(bmp: Bitmap, centerX: Int, centerY: Int, @FloatRange(from = 100.0, to = 200.0) strength: Float): Bitmap {
    val width = bmp.width
    val height = bmp.height
    val bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.RGB_565)
    var pixR = 0
    var pixG = 0
    var pixB = 0
    var pixColor = 0
    var newR = 0
    var newG = 0
    var newB = 0
    val radius = Math.min(centerX, centerY)
    val pixels = IntArray(width * height)
    bmp.getPixels(pixels, 0, width, 0, 0, width, height)
    var pos = 0
    var i = 1
    val length = height - 1
    while (i < length) {
        var k = 1
        val len = width - 1
        while (k < len) {
            pos = i * width + k
            pixColor = pixels[pos]
            pixR = Color.red(pixColor)
            pixG = Color.green(pixColor)
            pixB = Color.blue(pixColor)
            newR = pixR
            newG = pixG
            newB = pixB

            // 计算当前点到光照中心的距离，平面座标系中求两点之间的距离
            val distance = (Math.pow((centerY - i).toDouble(), 2.0) + Math.pow((centerX - k).toDouble(), 2.0)).toInt()
            if (distance < radius * radius) { // 按照距离大小计算增加的光照值
                val result = (strength * (1.0 - Math.sqrt(distance.toDouble()) / radius)).toInt()
                newR = pixR + result
                newG = pixG + result
                newB = pixB + result
            }
            newR = Math.min(255, Math.max(0, newR))
            newG = Math.min(255, Math.max(0, newG))
            newB = Math.min(255, Math.max(0, newB))
            pixels[pos] = Color.argb(255, newR, newG, newB)
            k++
        }
        i++
    }
    bitmap.setPixels(pixels, 0, width, 0, 0, width, height)
    return bitmap
}

/**
 * 模糊图片
 *
 * 先缩小原图，对小图进行模糊，再放大回原先尺寸
 *
 * @param src     源图片
 * @param scale   缩放比例(0...1)
 * @param radius  模糊半径(0...25)
 * @param recycle 是否回收
 * @return 模糊后的图片
 */
fun getBitmapfastBlur(src: Bitmap, @FloatRange(from = 0.0, to = 1.0, fromInclusive = false) scale: Float, @FloatRange(from = 0.0, to = 25.0, fromInclusive = false) radius: Float, recycle: Boolean): Bitmap? {
    if (isEmptyBitmap(src)) {
        return null
    }
    val width = src.width
    val height = src.height
    val matrix = Matrix()
    matrix.setScale(scale, scale)
    var scaleBitmap = Bitmap.createBitmap(src, 0, 0, src.width, src.height, matrix, true)
    val paint = Paint(Paint.FILTER_BITMAP_FLAG or Paint.ANTI_ALIAS_FLAG)
    val canvas = Canvas()
    val filter = PorterDuffColorFilter(Color.TRANSPARENT, PorterDuff.Mode.SRC_ATOP)
    paint.colorFilter = filter
    canvas.scale(scale, scale)
    canvas.drawBitmap(scaleBitmap!!, 0f, 0f, paint)
    scaleBitmap = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
        renderScriptBlur(scaleBitmap, radius, recycle)
    } else {
        stackBlur(scaleBitmap, radius.toInt(), recycle)
    }
    if (scale == 1f) {
        return scaleBitmap
    }
    val ret = Bitmap.createScaledBitmap(scaleBitmap!!, width, height, true)
    if (scaleBitmap != null && !scaleBitmap.isRecycled) {
        scaleBitmap.recycle()
    }
    if (recycle && !src.isRecycled) {
        src.recycle()
    }
    return ret
}

/**
 * renderScript 模糊图片
 *
 * API 大于 17
 *
 * @param src     源图片
 * @param radius  模糊半径(0...25)
 * @param recycle 是否回收
 * @return 模糊后的图片
 */
@TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1)
fun renderScriptBlur(src: Bitmap?, @FloatRange(from = 0.0, to = 25.0, fromInclusive = false) radius: Float, recycle: Boolean): Bitmap? {
    if (isEmptyBitmap(src)) {
        return null
    }
    var rs: RenderScript? = null
    val ret = if (recycle) src else src!!.copy(src.config, true)
    try {
        rs = RenderScript.create(application)
        rs.messageHandler = RSMessageHandler()
        val input = Allocation.createFromBitmap(rs, ret, Allocation.MipmapControl.MIPMAP_NONE, Allocation.USAGE_SCRIPT)
        val output = Allocation.createTyped(rs, input.type)
        val blurScript = ScriptIntrinsicBlur.create(rs, Element.U8_4(rs))
        blurScript.setInput(input)
        blurScript.setRadius(radius)
        blurScript.forEach(output)
        output.copyTo(ret)
    } finally {
        rs?.destroy()
    }
    return ret
}

/**
 * stack 模糊图片
 *
 * @param src     源图片
 * @param radius  模糊半径
 * @param recycle 是否回收
 * @return stack 模糊后的图片
 */
fun stackBlur(src: Bitmap?, radius: Int, recycle: Boolean): Bitmap? {
    val ret = if (recycle) src else src!!.copy(src.config, true)
    if (radius < 1) {
        return null
    }
    val w = ret!!.width
    val h = ret.height
    val pix = IntArray(w * h)
    ret.getPixels(pix, 0, w, 0, 0, w, h)
    val wm = w - 1
    val hm = h - 1
    val wh = w * h
    val div = radius + radius + 1
    val r = IntArray(wh)
    val g = IntArray(wh)
    val b = IntArray(wh)
    var rsum: Int
    var gsum: Int
    var bsum: Int
    var x: Int
    var y: Int
    var i: Int
    var p: Int
    var yp: Int
    var yi: Int
    var yw: Int
    val vmin = IntArray(Math.max(w, h))
    var divsum = div + 1 shr 1
    divsum *= divsum
    val dv = IntArray(256 * divsum)
    i = 0
    while (i < 256 * divsum) {
        dv[i] = i / divsum
        i++
    }
    yi = 0
    yw = yi
    val stack = Array(div) { IntArray(3) }
    var stackpointer: Int
    var stackstart: Int
    var sir: IntArray
    var rbs: Int
    val r1 = radius + 1
    var routsum: Int
    var goutsum: Int
    var boutsum: Int
    var rinsum: Int
    var ginsum: Int
    var binsum: Int
    y = 0
    while (y < h) {
        bsum = 0
        gsum = bsum
        rsum = gsum
        boutsum = rsum
        goutsum = boutsum
        routsum = goutsum
        binsum = routsum
        ginsum = binsum
        rinsum = ginsum
        i = -radius
        while (i <= radius) {
            p = pix[yi + Math.min(wm, Math.max(i, 0))]
            sir = stack[i + radius]
            sir[0] = p and 0xff0000 shr 16
            sir[1] = p and 0x00ff00 shr 8
            sir[2] = p and 0x0000ff
            rbs = r1 - Math.abs(i)
            rsum += sir[0] * rbs
            gsum += sir[1] * rbs
            bsum += sir[2] * rbs
            if (i > 0) {
                rinsum += sir[0]
                ginsum += sir[1]
                binsum += sir[2]
            } else {
                routsum += sir[0]
                goutsum += sir[1]
                boutsum += sir[2]
            }
            i++
        }
        stackpointer = radius
        x = 0
        while (x < w) {
            r[yi] = dv[rsum]
            g[yi] = dv[gsum]
            b[yi] = dv[bsum]
            rsum -= routsum
            gsum -= goutsum
            bsum -= boutsum
            stackstart = stackpointer - radius + div
            sir = stack[stackstart % div]
            routsum -= sir[0]
            goutsum -= sir[1]
            boutsum -= sir[2]
            if (y == 0) {
                vmin[x] = Math.min(x + radius + 1, wm)
            }
            p = pix[yw + vmin[x]]
            sir[0] = p and 0xff0000 shr 16
            sir[1] = p and 0x00ff00 shr 8
            sir[2] = p and 0x0000ff
            rinsum += sir[0]
            ginsum += sir[1]
            binsum += sir[2]
            rsum += rinsum
            gsum += ginsum
            bsum += binsum
            stackpointer = (stackpointer + 1) % div
            sir = stack[stackpointer % div]
            routsum += sir[0]
            goutsum += sir[1]
            boutsum += sir[2]
            rinsum -= sir[0]
            ginsum -= sir[1]
            binsum -= sir[2]
            yi++
            x++
        }
        yw += w
        y++
    }
    x = 0
    while (x < w) {
        bsum = 0
        gsum = bsum
        rsum = gsum
        boutsum = rsum
        goutsum = boutsum
        routsum = goutsum
        binsum = routsum
        ginsum = binsum
        rinsum = ginsum
        yp = -radius * w
        i = -radius
        while (i <= radius) {
            yi = Math.max(0, yp) + x
            sir = stack[i + radius]
            sir[0] = r[yi]
            sir[1] = g[yi]
            sir[2] = b[yi]
            rbs = r1 - Math.abs(i)
            rsum += r[yi] * rbs
            gsum += g[yi] * rbs
            bsum += b[yi] * rbs
            if (i > 0) {
                rinsum += sir[0]
                ginsum += sir[1]
                binsum += sir[2]
            } else {
                routsum += sir[0]
                goutsum += sir[1]
                boutsum += sir[2]
            }
            if (i < hm) {
                yp += w
            }
            i++
        }
        yi = x
        stackpointer = radius
        y = 0
        while (y < h) {

            // Preserve alpha channel: ( 0xff000000 & pix[yi] )
            pix[yi] = -0x1000000 and pix[yi] or (dv[rsum] shl 16) or (dv[gsum] shl 8) or dv[bsum]
            rsum -= routsum
            gsum -= goutsum
            bsum -= boutsum
            stackstart = stackpointer - radius + div
            sir = stack[stackstart % div]
            routsum -= sir[0]
            goutsum -= sir[1]
            boutsum -= sir[2]
            if (x == 0) {
                vmin[y] = Math.min(y + r1, hm) * w
            }
            p = x + vmin[y]
            sir[0] = r[p]
            sir[1] = g[p]
            sir[2] = b[p]
            rinsum += sir[0]
            ginsum += sir[1]
            binsum += sir[2]
            rsum += rinsum
            gsum += ginsum
            bsum += binsum
            stackpointer = (stackpointer + 1) % div
            sir = stack[stackpointer]
            routsum += sir[0]
            goutsum += sir[1]
            boutsum += sir[2]
            rinsum -= sir[0]
            ginsum -= sir[1]
            binsum -= sir[2]
            yi += w
            y++
        }
        x++
    }
    ret.setPixels(pix, 0, w, 0, 0, w, h)
    return ret
}

/**
 * 将图片保存到磁盘中
 *
 * @param bitmap
 * @param file   图片保存目录——不包含图片名
 * @param path   图片保存文件路径——包含图片名
 * @return
 */
fun saveBitmap(bitmap: Bitmap?, file: File, path: File?): Boolean {
    var success = false
    val bytes = getBytes(bitmap, 100)
    var out: OutputStream? = null
    try {
        if (!file.exists() && file.isDirectory) {
            file.mkdirs()
        }
        out = FileOutputStream(path)
        out.write(bytes)
        out.flush()
        success = true
    } catch (e: Exception) {
        e.printStackTrace()
    } finally {
        if (out != null) {
            try {
                out.close()
            } catch (e: IOException) {
                e.printStackTrace()
            }
        }
    }
    return success
}

/**
 * bitmap保存到指定路径
 *
 * @param file 图片的绝对路径
 * @param file 位图
 * @return bitmap
 */
fun saveFile(file: String?, bmp: Bitmap?): Boolean {
    if (TextUtils.isEmpty(file) || bmp == null) return false
    val f = File(file)
    if (f.exists()) {
        f.delete()
    } else {
        val p = f.parentFile
        if (!p.exists()) {
            p.mkdirs()
        }
    }
    try {
        val out = FileOutputStream(f)
        bmp.compress(CompressFormat.JPEG, 100, out)
        out.flush()
        out.close()
    } catch (e: IOException) {
        e.printStackTrace()
        return false
    }
    return true
}